﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Socium.Domain;
using Socium.Domain.Collections;
using Socium.Presentation;

namespace Socium.TestEditor {
	class MainViewModel : ViewModelBase {
		public MainViewModel(UserContext user_context) {
			_user_context = user_context;
			Manager = new DialogFormViewService();

			OpenCommand = new Command(OnOpen);
			SaveCommand = new Command(Save, CanSave);
			NewTestCommand = new Command(OnNewTest, CanSave);
		}

		Database _database;
		string _path;

		readonly UserContext _user_context;

		public IFormViewService Manager { get; private set; }

		readonly ObservableCollection<TestTreeItem> _tests = new ObservableCollection<TestTreeItem>();

		public ICollection<TestTreeItem> Tests {
			get { return _tests; }
		}

		void Update() {
			_tests.CollectionChanged -= OnTestsCollectionChanged;

			try {
				_tests.Clear();

				if (_database == null) {
					return;
				}

				var items = _database.Tests.Select(test => new TestTreeItem(test, _tests));

				_tests.AddRange(items);
			}
			finally {
				_tests.CollectionChanged += OnTestsCollectionChanged;
			}
		}

		void OnTestAdded(TestTreeItem item) {
			_database.Tests.Add(item.Model);
		}

		void OnTestRemoved(TestTreeItem item) {
			_database.Tests.Remove(item.Model);
		}

		void OnTestsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
			if (e.OldItems != null) {
				foreach (TestTreeItem old_item in e.OldItems) {
					OnTestRemoved(old_item);
				}
			}
			
			if (e.NewItems != null) {
				foreach (TestTreeItem new_item in e.NewItems) {
					OnTestAdded(new_item);
				}
			}
		}

		#region Open

		public ICommand OpenCommand { get; private set; }

		void OnOpen() {
			var path = _user_context.QueryDatabasePath();
			if (path == null) {
				return;
			}

			_database = Database.Load(path);
			_path = path;

			Update();
		}

		#endregion

		#region Save

		public ICommand SaveCommand { get; private set; }

		bool CanSave() {
			return _database != null && _path != null;
		}

		void Save() {
			if (!CanSave()) {
				throw new InvalidOperationException();
			}

			_database.Save(_path);
		}

		#endregion

		#region New test

		public ICommand NewTestCommand { get; private set; }

		void OnNewTest() {
			var view_model = new TestViewModel();
			view_model.ModelCreated += model => {
				var item = new TestTreeItem(model, _tests);
				view_model.ModelUpdated += item.Update;

				_tests.Add(item);
			};

			Manager.Show(view_model);
		}

		#endregion
	}
}
